<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./style/index.css">
    <title>造轮子·Vue calculator</title>
</head>

<body>
    <div id="calculator">
        <cal-output :value="result"></cal-output>
        <cal-button v-for="(value,index) in keyboardValues.slice(0,16)" :value="value" :key="index"
            @userclick="handleInput"></cal-button>
        <!-- 出于设计，“0”这个按钮要特殊处理 -->
        <cal-button value="0" special-class="cal-button-zero" @userclick="handleInput"></cal-button>
        <!-- 剩余的按钮，key值添加reset -->
        <cal-button v-for="(value,index) in keyboardValues.slice(-2)" :value="value" :key="'reset'+index"
            @userclick="handleInput"></cal-button>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script type="module">
        // 引入计算器按钮、输入框组件
        import calButton from "./src/button.js";
        import calOutput from './src/output.js';
        // 按钮数据
        const keyboardValues = ['AC', '+/-', '%', '÷', '7', '8', '9', '×',
            '4', '5', '6', '-', '1', '2', '3', '+', '0', '.', '='];
        // 安全输入长度
        const NUM_LENGTH = 14;
        const NUM_PRECISE = 13;
        // 操作符哈希表
        const operatorMap = {
            '%': (value) => {
                let currNum = parseFloat(value) / 100;
                // return String(handleFloat(currNum, NUM_PRECISE));
                return String(currNum);
            },
            '+/-': (value) => {
                if (value === '0') return '0';// edge case
                return parseFloat(value) > 0 ? "-" + value : value.slice(1);
            },
            'AC': (value, vm) => {
                // 所有数据清空
                vm.operationStack = [];
                vm.numStack = [];
                vm.operatorIn = false;
                return "0";
            },
            '.': (value, vm) => {
                return vm.result + '.';
            },
            '+': (value, vm) => {
                return handleOperator(value, "+", vm);
            },
            '-': (value, vm) => {
                return handleOperator(value, "-", vm);
            },
            '×': (value, vm) => {
                return handleOperator(value, "×", vm);
            },
            '÷': (value, vm) => {
                return handleOperator(value, "÷", vm);
            },
            '=': (value, vm) => {
                return calFinalRes(value, vm);
            }
        };

        // 处理四则元素符号函数--->当前结果、操作符、vm实例
        function handleOperator(value, operator, vm) {
            // 如果之前的操作不是使用操作符(正常操作)
            if (vm.operatorIn === false) {
                vm.operatorIn = true;
                vm.numStack.push(value);
                // 如果当前操作符栈数量 ＞ 1
                if (vm.operationStack.length >= 1) {
                    let num1 = vm.numStack.pop();
                    let num2 = vm.numStack.pop();
                    let currOprator = vm.operationStack.pop();// 出栈之前的操作符
                    let currNum = 0;
                    if (currOprator === "+") {
                        currNum = parseFloat(num1) + parseFloat(num2);
                    } else if (currOprator === "-") {
                        currNum = parseFloat(num2) - parseFloat(num1);
                    } else if (currOprator === "×") {
                        currNum = parseFloat(num1) * parseFloat(num2);
                    } else if (currOprator === "÷") {
                        currNum = parseFloat(num2) / parseFloat(num1);
                    }

                    value = String(currNum);
                    // 新结果和新操作符需要入栈
                    vm.operationStack.push(operator);// 新操作符入栈
                    vm.numStack.push(value);
                    return value;
                }
                vm.operationStack.push(operator);
                return value;
            } else {
                vm.operationStack.pop();// 最近的操作符出栈
                vm.operationStack.push(operator);
                return value;
            }
        }

        // 处理浮点数精度问题
        function handleFloat(value, precise) {
            let currValue = value.toPrecision(precise);
            return currValue.length > NUM_LENGTH ? currValue.slice(0, NUM_LENGTH) : currValue
        }

        // 计算当前结果 ---> 
        function calFinalRes(value, vm) {
            if (value !== vm.numStack[vm.numStack.length - 1] && vm.numStack.length > 0) {
                let currNum = vm.numStack.pop();
                let currOperator = vm.operationStack.pop();
                if (currOperator === "+") {
                    currNum = parseFloat(value) + parseFloat(currNum);
                } else if (currOperator === "-") {
                    currNum = parseFloat(currNum) - parseFloat(value);
                } else if (currOperator === "×") {
                    currNum = parseFloat(value) * parseFloat(currNum);
                } else if (currOperator === "÷") {
                    currNum = parseFloat(currNum) / parseFloat(value);
                }
                return String(currNum);
            }
            return String(value);
        }

        // 主APP位置挂载
        const app = new Vue({
            name: 'Vue-Calculator',
            el: "#calculator",
            // 组件注册
            components: {
                'cal-button': calButton,
                'cal-output': calOutput
            },
            // 数据选项
            data() {
                return {
                    keyboardValues,
                    result: "0",
                    operationStack: [],
                    numStack: [],
                    operatorIn: false
                }
            },
            // 方法选项
            methods: {
                // 处理用户输入方法
                handleInput(value) {
                    if (this.resHasPoint(value)) return; // 如果结果已经存在小数点，那就直接返回
                    if (operatorMap[value]) {// 如果当前触及是运算操作符
                        let currValue = operatorMap[value](this.result, this);
                        this.result = this.lengthIsValid(currValue) ? currValue : handleFloat(parseFloat(currValue), NUM_PRECISE);
                    } else {
                        // 先判断是否正在公式计算当中
                        if (this.operatorIn === true) {
                            this.result = '0';
                        }
                        let currValue = this.startWithZero() ? value : this.result + value;
                        if (this.lengthIsValid(currValue)) {
                            this.result = currValue;
                        }
                        this.operatorIn = false;// 恢复操作符运行
                    }
                },
                // 判断数字位数方法是否合法
                lengthIsValid(strNum) {
                    return strNum.length <= NUM_LENGTH;
                },
                // 判断开头是否为零
                startWithZero() {
                    return this.result.match(/^0/) && this.result.length === 1
                },
                // 检测结果中是否已经存在小数点
                resHasPoint(value) {
                    // console.log(value)
                    return this.result.indexOf(".") !== -1 && value === ".";
                }
            },
        });
    </script>
</body>

</html>